package main

import (
	//"fmt"
	"crypto/hmac"
	"crypto/sha1"
	"encoding/json"
	"io/ioutil"
	"math/rand"
	"strconv"
	"time"

	"log"

	"net/http"
	"net/url"

	"strings"

	_ "github.com/go-sql-driver/mysql"
)

func init() {
	//init
}

/*
调用阿里云的云直播API，取得在线人数
https://helpcdn.aliyun.com/document_detail/35412.html
注意：
    URL的多个提交值以字典方式排序
    取得签名值，给URL签名
*/
const Format = "JSON"

type Stu_Aliyun_ZhiBo struct {
	Action           string
	AccessKeyId      string
	AccessKeySecret  string
	Format           string
	Version          string
	Signature        string
	SignatureMethod  string
	SignatureNonce   string
	SignatureVersion string
	Timestamp        string
}

type stu_LiveStreamOnlineUserNumInfo struct {
	LiveStreamOnlineUserNumInfo []struct {
		StreamUrl  string // 	直播流的URL
		UserNumber int    //直播流的在线人数
		Time       string //统计时刻 UTC时间
	}
}
type stu_LiveStreamOnlineUserNum struct {
	TotalUserNumber int                             //所有流的用户数总和
	OnlineUserInfo  stu_LiveStreamOnlineUserNumInfo //每条直播流的用户数信息
	RequestId       string
}

func (this *Stu_Aliyun_ZhiBo) Init() {
	this.Format = "JSON"
	this.Version = "2016-11-01"
	this.AccessKeyId = "LTAIuTd53I4mVQUq"
	this.AccessKeySecret = "eXZQVDC2hOW4aWQLxFLd5qkOgmAu1v"
	this.SignatureMethod = "HMAC-SHA1"
	this.SignatureVersion = "1.0"
	subhour, _ := time.ParseDuration("-5m")
	//时间改为5分钟之前
	this.Timestamp = time.Now().Add(subhour).UTC().Format("2006-01-02T15:04:05Z") //请求的时间戳。日期格式按照ISO8601标准表示，并需要使用UTC时间。格式为：YYYY-MM-DDThh:mm:ssZ。例如，2014-11-11T12:00:00Z（为北京时间2014年11月11日20点0分0秒）
	log.Println("传入时间：", this.Timestamp)
	this.SignatureNonce = strconv.FormatInt(rand.New(rand.NewSource(time.Now().UnixNano())).Int63(), 10) //唯一随机数，用于防止网络重放攻击。用户在不同请求间要使用不同的随机数值

}

func (this *Stu_Aliyun_ZhiBo) GetOnlineUserNum1(domainName string) (err error) {
	var (
		mvalues url.Values
		murl    *url.URL
	)
	log.Println("使用URL和Values")
	this.Action = "DescribeLiveStreamOnlineUserNum"
	murl, err = url.Parse("https://live.aliyuncs.com")
	if err != nil {
		log.Println("解析url有错误 ：", err)
		return err
	}
	log.Printf("URL：%s，URL编码：%s", murl.String(), url.PathEscape(murl.String()))
	mvalues = url.Values{}
	mvalues.Add("AccessKeyId", this.AccessKeyId)
	mvalues.Add("Action", this.Action)
	mvalues.Add("DomainName", domainName)
	mvalues.Add("Format", this.Format)
	mvalues.Add("SignatureMethod", this.SignatureMethod)
	mvalues.Add("SignatureNonce", this.SignatureNonce)
	mvalues.Add("SignatureVersion", this.SignatureVersion)
	mvalues.Add("Timestamp", this.Timestamp)
	mvalues.Add("Version", this.Version)
	//log.Printf("Values输出：%s", mvalues)
	log.Printf("Values Encode编码输出：%s", mvalues.Encode()) //把timestamp里的:号格式化了，不能够用作string输出
	//将Values加入到URl中
	murl.RawQuery = mvalues.Encode()
	//log.Println("url  Scheme:", murl.Scheme)
	//log.Println("url Opaque:", murl.Opaque)
	//log.Printf("URL：%s \n，URL编码：%s", murl.String(), url.PathEscape(murl.String()))

	//签名机验证
	//vSha1 := sha1.New()
	//io.WriteString(vSha1, this.AccessKeyId)
	key := []byte(this.AccessKeySecret + "&")
	mac := hmac.New(sha1.New, key)
	mac.Write([]byte(murl.String())) //将要签名的URL写入hmac
	//求出签名值
	this.Signature = string(mac.Sum(nil))
	log.Printf("签名值 ：%x", mac.Sum(nil)) ////签名值

	//将签名写入URL
	mvalues.Add("Signature", this.Signature)
	//将Values加入到URl中
	murl.RawQuery = mvalues.Encode()
	log.Println("url  Scheme:", murl.Scheme)
	log.Println("url Opaque:", murl.Opaque)
	log.Printf("URL：%s \n，URL编码：%s", murl.String(), url.PathEscape(murl.String()))
	//得到签名后的URL：murl.String()

	//进行http get请求，测试结果
	resp, err := http.Get(murl.String())
	if err != nil {
		// handle error
		log.Println("http.Get出错！,err:", err)
	}

	defer resp.Body.Close()

	log.Println("返回http状态码：", resp.StatusCode)
	if resp.StatusCode == 200 {
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			// handle error
			log.Println(" ioutil.ReadAll(resp.Body)出错！,err:", err)
		}
		log.Println("阿里API返回：\n", string(body))
		var ss stu_LiveStreamOnlineUserNum
		err = json.Unmarshal(body, &ss)
		if err != nil {
			log.Println("解析数据转为结构体时出错：", err)
			return err
		}
		log.Println("在线总人数：", ss.TotalUserNumber)
		//log.Println("当前流的在线总人数：", ss.OnlineUserInfo[0].UserNumber)
	} else {
		log.Println("调用API出错，返回数据：")
		return err
	}
	return err
}

func (this *Stu_Aliyun_ZhiBo) GetOnlineUserNum(domainName string) (err error) {
	//将url生成签名并添加进去
	var (
		Url []string
	)
	const ACTION = "DescribeLiveStreamOnlineUserNum"                                                     //获取在线直播流的在线人数，支持实时查询和基于时间范围的查询；
	this.Timestamp = time.Now().UTC().Format("2006-01-02T15:04:05Z")                                     //请求的时间戳。日期格式按照ISO8601标准表示，并需要使用UTC时间。格式为：YYYY-MM-DDThh:mm:ssZ。例如，2014-11-11T12:00:00Z（为北京时间2014年11月11日20点0分0秒）
	this.SignatureNonce = strconv.FormatInt(rand.New(rand.NewSource(time.Now().UnixNano())).Int63(), 10) //唯一随机数，用于防止网络重放攻击。用户在不同请求间要使用不同的随机数值
	Url = append(Url, "https://live.aliyuncs.com?")
	Url = append(Url, "AccessKeyId")
	Url = append(Url, "=")
	Url = append(Url, this.AccessKeyId)
	Url = append(Url, "&")
	Url = append(Url, "Action")
	Url = append(Url, "=")
	Url = append(Url, "DescribeLiveStreamOnlineUserNum")
	Url = append(Url, "&")
	Url = append(Url, "DomainName")
	Url = append(Url, "=")
	Url = append(Url, domainName)
	Url = append(Url, "&")
	Url = append(Url, "Format")
	Url = append(Url, "=")
	Url = append(Url, this.Format)
	Url = append(Url, "&")
	Url = append(Url, "SignatureMethod")
	Url = append(Url, "=")
	Url = append(Url, this.SignatureMethod)
	Url = append(Url, "&")
	Url = append(Url, "SignatureNonce")
	Url = append(Url, "=")
	Url = append(Url, this.SignatureNonce)
	Url = append(Url, "&")
	Url = append(Url, "SignatureVersion")
	Url = append(Url, "=")
	Url = append(Url, this.SignatureVersion)
	Url = append(Url, "&")
	Url = append(Url, "Timestamp")
	Url = append(Url, "=")
	Url = append(Url, this.Timestamp)
	Url = append(Url, "&")
	Url = append(Url, "Version")
	Url = append(Url, "=")
	Url = append(Url, this.Version)
	//签名机验证
	log.Println("使用AccessKeySecret签名后的URl为：", url.PathEscape(strings.Join(Url, "")))
	//vSha1 := sha1.New()
	//io.WriteString(vSha1, this.AccessKeyId)
	key := []byte(this.AccessKeySecret + "&")
	mac := hmac.New(sha1.New, key)
	mac.Write([]byte(url.PathEscape(strings.Join(Url, "")))) //将要签名的URL写入hmac
	log.Printf("签名值 ：%x", mac.Sum(nil))                      ////签名值
	Url = append(Url, "&")
	Url = append(Url, "Signature")
	Url = append(Url, "=")
	Url = append(Url, this.Signature)
	return err
}

func main() {
	var (
		my Stu_Aliyun_ZhiBo
	)
	my.Init()
	my.GetOnlineUserNum("l.kjdll.com")
	my.GetOnlineUserNum1("l.kjdll.com")
}
